package org.jeecg.modules.wflow.workflow.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.jeecg.modules.wflow.mapper.WflowModelsMapper;
import org.jeecg.modules.wflow.workflow.bean.process.ProcessNode;
import org.jeecg.modules.wflow.workflow.bean.process.form.Form;
import org.jeecg.modules.wflow.workflow.bean.process.form.FormPerm;
import org.jeecg.modules.wflow.workflow.bean.process.props.ApprovalProps;
import org.jeecg.modules.wflow.workflow.bean.process.props.CcProps;
import org.jeecg.modules.wflow.workflow.bean.process.props.RootProps;
import org.jeecg.modules.wflow.workflow.service.FormService;
import org.jeecg.modules.wflow.workflow.service.ProcessNodeCatchService;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : willian fu
 * @date : 2022/8/24
 */
@Service
public class FormServiceImpl implements FormService {

    @Autowired
    private ProcessNodeCatchService nodeCatchService;

    @Autowired
    private WflowModelsMapper modelsMapper;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    @Override
    public Map<String, Object> getProcessInstanceFormData(String instanceId) {
        return historyService.createHistoricVariableInstanceQuery()
                .processInstanceId(instanceId).variableNameLike("field%").list()
                .stream().collect(Collectors.toMap(
                        HistoricVariableInstance::getVariableName,
                        HistoricVariableInstance::getValue)
                );
    }

    @Override
    public Map<String, Object> getProcessInstanceFormDataLike(String instanceId, String likeName) {
        return null;
    }

    @Override
    public Object getProcessInstanceFormDataSingle(String instanceId, String fieldName) {
        return null;
    }

    @Override
    public <T> T getProcessInstanceFormDataSingleByType(String instanceId, String fieldName, Class<T> clazz) {
        return null;
    }

    @Override
    public void updateInstanceFormData(String instanceId, Map<String, Object> formData) {
        Map<String, Object> dataMap = new HashMap<>();
        formData.forEach((k, v) -> {
            Object variable = runtimeService.getVariable(instanceId, k);
            //做下比较，不同就修改
            if (Objects.isNull(variable) && Objects.nonNull(v) || !variable.equals(formData.get(k))){
                dataMap.put(k, v);
            }
        });
        if (CollectionUtil.isNotEmpty(dataMap)){
            runtimeService.setVariables(instanceId, dataMap);
        }
    }

    @Override
    public List<Form> filterFormByPermConfigForRoot(List<Form> forms, RootProps rootProps) {
        Map<String, FormPerm.PermEnum> permEnumMap = rootProps.getFormPerms().stream().collect(Collectors.toMap(FormPerm::getId, FormPerm::getPerm));
        return doFilterForm(forms, null, permEnumMap, FormPerm.PermEnum.E);
    }

    @Override
    public List<Form> getFormsByProcessCodeFilterPerm(String currentNode, String code) {
        //TODO 同一个人在不同节点的表单权限可能不一样，按最大权限过滤
        String formItems = modelsMapper.selectById(code).getFormItems();
        ProcessNode<?> node = nodeCatchService.getProcessNodeById(code, currentNode);
        List<FormPerm> formPerms = null;
        FormPerm.PermEnum defaultPerm = FormPerm.PermEnum.R;
        switch (node.getType()){
            case ROOT:
                formPerms = ((RootProps) node.getProps()).getFormPerms();
                defaultPerm = FormPerm.PermEnum.E;
                break;
            case APPROVAL:
                formPerms = ((ApprovalProps) node.getProps()).getFormPerms();
                break;
            case CC:
                formPerms = ((CcProps) node.getProps()).getFormPerms();
                break;
            default:
                formPerms = Collections.emptyList();
                break;
        }
        //转换map
        Map<String, FormPerm.PermEnum> permEnumMap = formPerms.stream().collect(Collectors.toMap(FormPerm::getId, FormPerm::getPerm));
        FormPerm.PermEnum finalDefaultPerm = defaultPerm;
        //过滤出有查看权限的表单
        return JSONObject.parseArray(formItems, Form.class).stream()
                .peek(item -> {
                    FormPerm.PermEnum perm = permEnumMap.getOrDefault(item.getId(), finalDefaultPerm);
                    item.setPerm(perm);
                }).filter(item -> !FormPerm.PermEnum.H.equals(item.getPerm()))
                .collect(Collectors.toList());
    }

    @Override
    public List<Form> filterFormAndDataByPermConfig(List<Form> forms, Map<String, Object> formData, ProcessNode<?> currentNode) {
        FormPerm.PermEnum defaultPerm = FormPerm.PermEnum.R;
        List<FormPerm> formPerms = Collections.emptyList();
        if (Objects.isNull(currentNode)){
            return doFilterForm(forms, formData, Collections.emptyMap(), defaultPerm);
        }
        switch (currentNode.getType()){
            case ROOT:
                formPerms = ((RootProps) currentNode.getProps()).getFormPerms();
                defaultPerm = FormPerm.PermEnum.E;
                break;
            case APPROVAL:
                formPerms = ((ApprovalProps) currentNode.getProps()).getFormPerms();
                break;
            case CC:
                formPerms = ((CcProps) currentNode.getProps()).getFormPerms();
                break;
        }
        Map<String, FormPerm.PermEnum> permEnumMap = formPerms.stream().collect(Collectors.toMap(FormPerm::getId, FormPerm::getPerm));
        return doFilterForm(forms, formData, permEnumMap, defaultPerm);
    }

    private List<Form> doFilterForm(List<Form> forms, Map<String, Object> formData, Map<String, FormPerm.PermEnum> permEnumMap, FormPerm.PermEnum defaultPerm){
        return forms.stream().filter(form -> {
            if ("SpanLayout".equals(form.getName())){
                form.setPerm(Objects.isNull(formData) ? FormPerm.PermEnum.E : FormPerm.PermEnum.R);
                JSONArray items = (JSONArray)form.getProps().get("items");
                form.getProps().put("items", doFilterForm(items.toJavaList(Form.class), formData, permEnumMap, defaultPerm));
            }else {
                FormPerm.PermEnum formPerm = permEnumMap.getOrDefault(form.getId(), defaultPerm);
                if (FormPerm.PermEnum.H.equals(formPerm)){
                    //去除对应数据
                    Optional.ofNullable(formData).ifPresent(data -> data.remove(form.getId()));
                    return false;
                }
                form.setPerm(formPerm);
            }
            return true;
        }).collect(Collectors.toList());
    }
}
